/*
 * Object   : CServer
 * Type     : Backend
 *
 * Narrator : Kamran H. Khan 
 * Email    : KAMRAN.KHAN@MaximaLabssolutions.com, KAMRANHK@gmail.com
 * 
 * Copyright :
 *            MaximaLabs Solutions (R) 2009
 * 
 * 
 * Description: 
 * Serves a base class for server objects
 * 
 * Revision History:
 * 
 * Date(MMM/dd/yy)      Owner           Description
 * ----------------------------------------------------------------------------------------------------------------------------------------------
 * May/30/09            Kamran H. Khan  Added skeleton code
 * May/30/09            Kamran H. Khan  Added more methods
 * May/30/09            Kamran H. Khan  Added Listen()
 *                                      -Send(), Start(), Stop()
 *                                      -StatusChange() event handler
 *                                      -Added ManageClient(), 
 *                                      -added threading pool management.
 * 
*/


using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.ComponentModel;
using System.Diagnostics;
using Maxima.Common;


namespace Maxima.Communicator
{
    public class CServer : CNetMgr, IDisposable
    {
        public TcpListener m_theSvr; //the main server object
        private bool m_bStopped;
        Thread m_thdListener;
        //CProcessor m_theProcessor;

        private bool m_bIsConnected = false;
        public bool IsConnected
        {
            get { return m_bIsConnected; }
        }

        private string m_strIP;
        [Category("Settings")]
        [Description("IP Address")]
        [BrowsableAttribute(true)]
        public string IP
        {
            get { return m_strIP; }
            set { m_strIP = value; }
        }

        private int m_nPort;

        [Category("Settings")]
        [Description("Port")]
        [BrowsableAttribute(true)]
        public int Port
        {
            get { return m_nPort; }
            set { m_nPort = value; }
        }

        public string m_strStatus;

        private List<TcpClient> m_lstClients = new List<TcpClient>();

        [Category("Settings")]
        [Description("Provides the list of connected clients")]
        [BrowsableAttribute(true)]
        public List<TcpClient> ListOfClients
        {
            get { return m_lstClients; }
        }

        public delegate void StatusChangeEventHandler(string strData);
        public event StatusChangeEventHandler OnStatusChange;


        /// <summary>
        /// Initializes a new instance of the <see cref="CServer"/> class.
        /// </summary>
        /// <param name="strIP">The STR IP.</param>
        /// <param name="nPort">The n port.</param>
        public CServer(string strIP, int nPort)
            : base(strIP, nPort, false)
        {
            m_strIP = strIP;
            m_nPort = nPort;

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Initialization success.", System.Diagnostics.EventLogEntryType.SuccessAudit);

            PropagateMessageToUpperLayer("Loading server...");


        }


        /// <summary>
        /// Starts this instance.
        /// </summary>
        public void Start()
        {
            //StartThread();
            //m_theProcessor.Init();
            //m_theProcessor = new CProcessor();//Initialise the main processor object

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method.", System.Diagnostics.EventLogEntryType.SuccessAudit);


            m_bStopped = false;

            m_thdListener = new Thread(delegate() { Listen(); });
            m_thdListener.IsBackground = true;
            m_thdListener.Start();

            PropagateMessageToUpperLayer("Server started.");
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "End.", System.Diagnostics.EventLogEntryType.SuccessAudit);
        }

        /// <summary>
        /// Listens this instance.
        /// </summary>
        private void Listen()
        {

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method.", System.Diagnostics.EventLogEntryType.Information);

            try
            {
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Trying to listen on (IP:Port): [" + m_strIP + ":" + m_nPort.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);
                m_theSvr = new TcpListener(IPAddress.Parse(m_strIP), Convert.ToInt32(m_nPort));
                m_theSvr.Start(int.Parse(CConstants.NO_OF_MAX_CLIENTS_SUPPORTED.ToString())); //the backlog, for now its 10
                m_bIsConnected = true;
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Started", System.Diagnostics.EventLogEntryType.Information);
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Running@[" + m_strIP + ":" + m_nPort.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);

                while (!m_bStopped)
                {
                    PropagateMessageToUpperLayer("Listening...");
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Listening", System.Diagnostics.EventLogEntryType.SuccessAudit);

                    if (m_theSvr == null)
                        break;

                    TcpClient thisClient = this.m_theSvr.AcceptTcpClient();

                    if (!IsValidClient(thisClient))
                    {
                        //CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Error: " + RxCodes.);;

                        CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Invalid connection, rejected :[" + thisClient.Client.RemoteEndPoint.ToString() + "]", EventLogEntryType.FailureAudit);
                        thisClient.Client.Close();
                        thisClient.Close();
                        thisClient = null;

                    }
                    else
                    {
                        PropagateMessageToUpperLayer(thisClient.Client.LocalEndPoint.ToString() + ">>New entry... : [" + thisClient.Client.LocalEndPoint.ToString() + "]");

                        CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, ">>New connection : [" + thisClient.Client.RemoteEndPoint.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);

                        //todo: add max limit check.
                        m_lstClients.Add(thisClient);
                        CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Added to list.", System.Diagnostics.EventLogEntryType.Information);
                        CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Concurrent connections: [" + m_lstClients.Count.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);
                        Thread thdManageClient = new Thread(new ParameterizedThreadStart(ManageClientEx));
                        thdManageClient.IsBackground = true;
                        thdManageClient.Start(thisClient);

                        CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Thread spawned.", System.Diagnostics.EventLogEntryType.Information);
                    }
                }
            }
            catch (Exception ex)
            {

                CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Unable to listen", ex);
                //Error(exc.Message);

            }

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "End.", System.Diagnostics.EventLogEntryType.SuccessAudit);
        }

        private bool IsValidClient(TcpClient thisClient)
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside");
            bool bStatus = false;//default status, passive mode of action.
            try
            {
                //Check the database to see if this IP is an acceptable IP, white list.
                if (true)//CDBHandler.IsValidIPEx(thisClient.Client.RemoteEndPoint.ToString()))
                {
                    bStatus = true;//lets say, it is.
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Valid client.");
                }
                else
                {
                    bStatus = false;//Unreachable - this case should never occur in case of simulation.
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Not a valid client.", EventLogEntryType.FailureAudit);
                }
            }
            catch (Exception ex)
            {
                CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Failed to validate client", ex);
            }

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "End");
            return bStatus;
        }


        private void ManageClientEx(object theClient)
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method", System.Diagnostics.EventLogEntryType.Information);
            
            TcpClient thisClient = (TcpClient)theClient;
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Connected. Managing client (IP:Port): [" + thisClient.Client.RemoteEndPoint.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);


            bool bShouldDisconnect = false;
            int nMessageCount = 0;
            int nHeaderBytes = 4;//should come from configuration.

            while (true)
            {
                try
                {
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Waiting for data", System.Diagnostics.EventLogEntryType.Information);

                    string strHeaderBytes = ReadData(thisClient.Client, //the client
                                                     nHeaderBytes, // bytes to be read
                                                     out bShouldDisconnect);//Invalid header bytes? disconnect this client.

                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Read bytes: [" + strHeaderBytes + "]");
                    if (bShouldDisconnect)
                    {
                        //Disconnect the client, if invalid header bytes.
                        m_lstClients.Remove(thisClient); thisClient.Close();
                        break;
                    }
                    else
                    {

                        int nDataReceived = 0;
                        string strRawMsg = string.Empty;
                        bool bReadable = int.TryParse(strHeaderBytes.ToString(), out nDataReceived);
                        if (!bReadable || nDataReceived < 0)
                        {
                            //Disconnect the client, if invalid header bytes.
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Invalid header bytes: [" + strHeaderBytes + "]; disconnecting [" + thisClient.Client.RemoteEndPoint.ToString() + "] ", System.Diagnostics.EventLogEntryType.FailureAudit);
                            m_lstClients.Remove(thisClient);
                            thisClient.Close();
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Concurrent connections: [" + m_lstClients.Count.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);
                            break;
                        }
                        else if (nDataReceived == 0)
                        {
                            //Echo if empty message.
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "0 bytes recieved; assuming a disconnect signal.");
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Sending disconnect acknowledge signal; echo 0 bytes.");
                            int nBytesSent = thisClient.Client.Send(System.Text.ASCIIEncoding.ASCII.GetBytes("0"));

                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Disconnecting:[" + thisClient.Client.RemoteEndPoint.ToString() + "] ", System.Diagnostics.EventLogEntryType.SuccessAudit);
                            m_lstClients.Remove(thisClient);
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Concurrent connections: [" + m_lstClients.Count.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);

                            thisClient.Close();
                            break;
                        }
                        else
                        {
                            //1. Delegate the incoming message to CSimHandler
                            //2. Have it process the message, prepare the corresponding response string
                            //3. Respond to client.
                            strRawMsg = ReadData(thisClient.Client, nDataReceived, out bShouldDisconnect);
                            //Throw to UI layer for processing.
                            PropagateMessageToUpperLayer(strRawMsg);//Btw, a not so good design. Should only be used if dealing with UI, otherwise push into some queue, process the message, and respond to client.

                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Message found: [" + strRawMsg + "]");
                            int nBytesSent = thisClient.Client.Send(System.Text.ASCIIEncoding.ASCII.GetBytes(strRawMsg.Length.ToString().PadLeft(4, '0').ToString() + strRawMsg));
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "SentTo(" + thisClient.Client.RemoteEndPoint.ToString() + "): [" + strRawMsg + "]", System.Diagnostics.EventLogEntryType.SuccessAudit);
                        
                            //Btw, worst class design.
                            //TODO: Revamp
                            //Solution 1: Producer/consumer architecture, push incoming messages into a queue; process, translate message, and respond. Prosposed, quality design.
                            //Solution 2: Integrate with the CSimHandler class, not a good design anyway.
                        }
                    }

                }
                catch (Exception ex)
                {
                    CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Non-compliant message format; bad client.", ex);
                    CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Kicking out:[" + thisClient.Client.RemoteEndPoint.ToString() + "] ");
                    thisClient.Close();
                    break;
                }
            }

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Messages processed for this channel: [" + nMessageCount.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "End", System.Diagnostics.EventLogEntryType.SuccessAudit);
        }



        string ReadData(Socket sckClient, int nBytesToRead, out bool bShouldDisconnect)
        {
            bShouldDisconnect = false;

            byte[] byteBuffer = new byte[nBytesToRead];
            Array.Clear(byteBuffer, 0, byteBuffer.Length);

            int nDataRead = 0;
            int nStartIndex = 0;
            int nBytesRead = 0;
            //while (nDataRead <= nBytesToRead)
            while (nDataRead < nBytesToRead)
            {
                try
                {
                    nBytesRead = sckClient.Receive(byteBuffer, nStartIndex, nBytesToRead - nStartIndex, SocketFlags.None);
                }
                catch (SocketException ex)
                {
                    CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "What went wrong? ", ex);

                }
                if (0 == nBytesRead)
                {
                    bShouldDisconnect = true;
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "0 bytes received; assuming disconnect signal");
                    break;
                }

                nDataRead += nBytesRead;
                nStartIndex += nBytesRead;
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Data : [" + Encoding.Default.GetString(byteBuffer, 0, nDataRead) + "]");
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Bytes read: " + nBytesRead.ToString());
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Bytes remaining: " + (nBytesToRead - nDataRead).ToString());



            }

            return Encoding.Default.GetString(byteBuffer, 0, nDataRead);
        }


        /// <summary>
        /// Manages the client.
        /// </summary>
        /// <param name="theClient">The client.</param>
        [Obsolete("Deffered; use ManageClientEx() instead", true)]
        private void ManageClient(object theClient)
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method", System.Diagnostics.EventLogEntryType.Information);

            TcpClient thisClient = (TcpClient)theClient;
            NetworkStream theCommLayer = thisClient.GetStream();

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Connected. Managing client (IP:Port): [" + thisClient.Client.RemoteEndPoint.ToString() + "]", System.Diagnostics.EventLogEntryType.Information);

            int nBytesRead = 0;
            ASCIIEncoding theEncoding = new ASCIIEncoding();
            while (true)
            {
                try
                {
                    byte[] bytMessage = new byte[READ_BUFFER_MAX_SIZE];

                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Waiting for data", System.Diagnostics.EventLogEntryType.Information);
                    nBytesRead = theCommLayer.Read(bytMessage, 0, bytMessage.Length);
                    if (nBytesRead == 0)
                        continue;

                    string strMsg = theEncoding.GetString(bytMessage);
                    strMsg = strMsg.Trim();// Normalize();
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "RX: [" + strMsg + "]", System.Diagnostics.EventLogEntryType.Information);

                    //Check if this is a logout request.
                    //this would never come.
                    if (IsCloseConnectionRequest(strMsg))
                    {
                        bool bRemoved = m_lstClients.Remove(thisClient); //remove from the list
                        break;
                    }
                    else
                    {
                        //Send("SVR_ECHO:[" + strMsg+"]");
                        //strMsg = m_theProcessor.Execute(strMsg);

                        //if (m_theProcessor.ResponseCode != null)
                        {
                            // if (m_theProcessor.ResponseCode.Equals(MaximaLabs.RxCodes.INVALID_CHANNEL))
                            {
                                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Kicking out:[" + thisClient.Client.RemoteEndPoint.ToString() + "] ", System.Diagnostics.EventLogEntryType.SuccessAudit);
                                thisClient.Close();
                                break;
                            }
                        }
                        //else
                        {
                            int nBytesSent = thisClient.Client.Send(System.Text.ASCIIEncoding.ASCII.GetBytes("SVR_ECHO:[" + strMsg + "]"));
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Sent:[" + thisClient.Client.RemoteEndPoint.ToString() + "] " + "SVR_ECHO:[" + strMsg + "]", System.Diagnostics.EventLogEntryType.SuccessAudit);
                        }
                    }

                }
                catch (Exception ex)
                {
                    //Error(ex.Message);
                    CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Couldnt manage client", ex);
                    thisClient.Close();
                    break;
                }
            }


            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "End", System.Diagnostics.EventLogEntryType.Information);

        }

        /// <summary>
        /// Replaces the non printables.
        /// </summary>
        /// <param name="strMsg">The STR MSG.</param>
        /// <returns></returns>
        private bool ReplaceNonPrintables(ref string strMsg)
        {
            bool bStatus = false;
            try
            {
                if (strMsg.StartsWith("\0"))
                {
                    strMsg = strMsg.Replace('\0', '?');
                    bStatus = true;//replaced.
                }

            }
            catch (Exception ex)
            {
                CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Error while replacing non printables", ex);
                //Error(exc.Message); 

            }

            return bStatus;
        }


        /// <summary>
        /// Determines whether [is close connection request] [the specified STR MSG].
        /// </summary>
        /// <param name="strMsg">The STR MSG.</param>
        /// <returns>
        /// 	<c>true</c> if [is close connection request] [the specified STR MSG]; otherwise, <c>false</c>.
        /// </returns>
        private bool IsCloseConnectionRequest(string strMsg)
        {
            if (strMsg.StartsWith(CLOSE_CONNECTION_REQUEST_CODE))//Check if its a logout intimation.
                return true;
            else return false;
        }

        /// <summary>
        /// Errors the specified STR MSG.
        /// </summary>
        /// <param name="strMsg">The STR MSG.</param>
        private void Error2(string strMsg)
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "ERROR: " + strMsg, System.Diagnostics.EventLogEntryType.Error);
            PropagateMessageToUpperLayer("ERROR: " + strMsg);
        }



        /// <summary>
        /// Logs the specified STR MSG.
        /// </summary>
        /// <param name="strMsg">The STR MSG.</param>
        private void PropagateMessageToUpperLayer(string strMsg)
        {
            m_strStatus = strMsg;// "\r\nSVR:" + 
            //OnStatusChange = new StatusChangeEventHandler();
            if (OnStatusChange != null)
                OnStatusChange(m_strStatus);

            //CHelper.Log(strMsg);
        }


        /// <summary>
        /// Sends the specified STR data.
        /// </summary>
        /// <param name="strData">The STR data.</param>
        /// <returns></returns>
        public int Send(string strData)
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method", System.Diagnostics.EventLogEntryType.Information);

            //StatusChangeEvent("ERROR: " + strMsg);

            int nBytesSent = 0;
            if (m_theSvr == null)
                return nBytesSent;

            try
            {
                int nIndexStart = strData.IndexOf("[");
                int nIndexEnd = strData.IndexOf("]");
                string strMsg = strData.Substring(1, nIndexEnd - 1);

                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Sending to client.", System.Diagnostics.EventLogEntryType.Information);
                bool bSent = false;
                foreach (TcpClient theClient in m_lstClients)
                {
                    try
                    {
                        if (!theClient.Client.RemoteEndPoint.ToString().Equals(strMsg))
                            continue;

                        if (theClient.Connected)
                        {
                            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Client connected", System.Diagnostics.EventLogEntryType.Information);
                            if (theClient.Client.Connected)
                            {
                                nBytesSent = theClient.Client.Send(System.Text.ASCIIEncoding.ASCII.GetBytes(strData));

                                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Sent:[" + strData + "]", System.Diagnostics.EventLogEntryType.SuccessAudit);

                                PropagateMessageToUpperLayer("\r\nTX: " + " [" + theClient.Client.RemoteEndPoint.ToString() + "] " + strData);
                                bSent = true;

                                break;
                            }
                            else
                            {
                                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Couldnt send:[" + strData + "]", System.Diagnostics.EventLogEntryType.FailureAudit);
                            }
                        }


                    }
                    catch (Exception ex)
                    {
                        //Error(exc.Message);
                        CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Error while sending data 2", ex);
                    }
                }
                if (!bSent)
                    CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Sent to none.", System.Diagnostics.EventLogEntryType.FailureAudit);
            }
            catch (Exception ex)
            {
                //Error(exc.Message);
                CLogger.GetInstance().Error(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Error while sending data", ex);
            }

            return nBytesSent;
        }



        /// <summary>
        /// Stops this instance.
        /// </summary>
        public void Stop()
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method", System.Diagnostics.EventLogEntryType.Information);

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Shutting down server", System.Diagnostics.EventLogEntryType.Information);

            if (m_thdListener != null)
            {
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Aborting thread(s)", System.Diagnostics.EventLogEntryType.Information);
                m_thdListener.Abort();
                m_thdListener = null;

                m_theSvr.Stop();
                m_theSvr = null;
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Abort success.", System.Diagnostics.EventLogEntryType.Information);

                if (m_lstClients != null)
                {
                    m_lstClients.Clear();
                }

                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Memory cleaned", System.Diagnostics.EventLogEntryType.Information);


            }
        }



        #region IDisposable Members

        void IDisposable.Dispose()
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside method", System.Diagnostics.EventLogEntryType.Information);

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Closing", System.Diagnostics.EventLogEntryType.Information);

            m_theSvr.Server.Close();

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Clearing", System.Diagnostics.EventLogEntryType.Information);

            m_lstClients.Clear();
            m_lstClients = null;

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Close success.", System.Diagnostics.EventLogEntryType.Information);

            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "End", System.Diagnostics.EventLogEntryType.Information);
        }

        #endregion
    }
}
